package mx.uach.compiladores;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Clase principal del analizador sintactico predictivo.
 * <ul>
 * <li>sent → exp +term ;</li>
 * <li>expr → expr - term | term</li>
 * <li>term → 0 | 1 | 2 | 3 |4 | 5 | 6 | 7 | 8 | 9 </li>
 * </ul>
 *
 * @author Jesus Manuel Garcia Rico
 * @version 1.0
 * @since 27/02/2014
 */
public class AnalizadorSintactico {

    private static final int FIN_SENT = ';';
    private static final int SUMA = '+';
    private static final int RESTA = '-';

    private int token;
    private String notacion;

    /**
     * Constructor principal de la clase
     */
    public AnalizadorSintactico() {
        this.token = -1;
        this.notacion = "";
    }
    
    public void iniciarAnalisis() throws IOException{
        this.sent();
    }
    
    public static void main(String[] args){
        try {
            AnalizadorSintactico analizador = new AnalizadorSintactico();
            analizador.iniciarAnalisis();
        } catch (IOException ex) {
            System.out.println("Ocurrio una anomalia" + ex.getMessage());
        }
    }

    /**
     * Hace referencia a una produccion gramatical, verifica que se componga los
     * elementos de las demas producciones más el final de sentencia.
     *
     * @throws IOException cuando no exsiste una entrada.
     */
    private void sent() throws IOException {
        this.siguiente(this.token);
        this.expr();
        if (this.token == FIN_SENT) {
            System.out.println(this.notacion);
        } else {
            throw new Error(String.format(
                    "Error de Sintaxis, se esperaba (%s)", (char) FIN_SENT));
        }
    }

    /**
     * Verifica quesa secuencia de esta producción sea valida (+ ó -).
     *
     * @throws IOException cuando no existe una entrada
     */
    private void expr() throws IOException {
        this.term();
        while (true) {
            if (this.token == SUMA) {
                this.siguiente(SUMA);
                term();
                this.notacion = String.format(
                        "%S%S", this.notacion, (char) SUMA);
            } else if (this.token == RESTA) {
                this.siguiente(RESTA);
                term();

            } else {
                return;
            }
        }
    }

    /**
     * Verifica que todas las terminales sean digitos.
     *
     * @throws IOException cuando no existe una entrada valida.
     */
    private void term() throws IOException {
        if (Character.isDigit((char) this.token)) {
            this.notacion = String.format("%S%S", 
                    this.notacion, (char) this.token);
            this.siguiente(this.token);
        } else {
            throw new Error(String.format(
                  "Error de sintaxi, token no valido: %s", (char) this.token));
        }
    }

    /**
     * Verifica que la secuencia de tokens sea valida y no sea corrupta.
     *
     * @param token caracter númerico.
     * @throws IOException cuando no existe una entrada valida
     */
    private void siguiente(int token) throws IOException {
        if (this.token == token) {
            this.token = System.in.read();
        } else {
            throw new Error(String.format(
                 "Error de sintaxis, token No valido: %s", (char) this.token));
        }
    }
}
